React Server Component
RSC / SC ↔ Client Component(CC)
https://ja.react.dev/reference/rsc/server-components
クライアントアプリケーションや SSR サーバとは別の環境で、バンドル前に事前にレンダーされます。
React Server Components の “server” とはこの別の環境を指しています。サーバコンポーネントは、CI サーバでビルド時に一度だけ実行することも、ウェブサーバを使用してリクエストごとに実行することもできます。
特徴
サーバサイドでのみ実行されるコンポーネント
従来の React における SSR でのコンポーネントは、ブラウザとサーバの両方で実行されていた
よく混同されるが、SSR とは異なる radish-miyazaki.icon
https://zenn.dev/dai_shi/articles/94affd526f4c8a
レンダリング結果 が異なる
RSC: RSC Payload
SSR: HTML
各々が独立しているので、同じプロセス、マシンで動かす必要もない
コンポーネントの JS ファイルがブラウザに送られることが無い
コンポーネントを 非同期関数 で書くことができる
コンポーネント上から直接外部 API のデータを取得し、レンダリングするといったことが可能に
code:tsx
async function getPosts() {
const data: { posts: Post[] } = await fetch('https://example.com/posts')
.then((res) => res.json());
return data.posts;
}
export default async function ServerComponent() {
const posts = getPosts()
return (
<div>
<h1>Posts</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>
<a href={post.url}>{post.title}</a>
</li>
))}
</ul>
</div>
)
}
fetch はコンポーネント内から呼び出さないようにする
理由
どういったデータを取得しているか分かりやすい
リクエストのメモ化の考慮漏れが起きづらい
https://nextjs.org/docs/app/building-your-application/data-fetching/fetching#request-memoization
リクエストウォーターフォール を避けるための並列取得
1. Promise.all を用いる
code:tsx
export default async function Page({ params, searchParams }: Props) {
const photo, category = await Promise.all([
getCategory(photo.categoryName),
getPhotos()
]);
// ...
}
2. 子 Server Component ごとにサーバサイドのデータを取得
コロケーション を意識した方法
e.g. Next.js における RSC
App Router 内で実装されるコンポーネントは、デフォルトで React Server Component として扱われる
https://nextjs.org/docs/app/building-your-application/rendering/server-components#using-server-components-in-nextjs
By default, Next.js uses Server Components.
RSC と CC は以下のようなフローでレンダリングされる
https://nextjs.org/docs/app/building-your-application/rendering/server-components#how-are-server-components-rendered
サーバサイド
Each chunk is rendered in two steps:
1. React renders Server Components into a special data format called the React Server Component Payload (RSC Payload).
2. Next.js uses the RSC Payload and Client Component JavaScript instructions to render HTML on the server.
1. RSC から RSC Payload をレンダリングする
RSC Payload は JSON を複数行にして ストリーム にしたもの
2. RSC Payload と CC から、初期表示のための HTML をレンダリングする(SSR)
クライアントには、生成した HTML と RSC Payload、CCの JS バンドル を送信する
クライアントサイド
Then, on the client:
1. The HTML is used to immediately show a fast non-interactive preview of the route - this is for the initial page load only.
2. The React Server Components Payload is used to reconcile the Client and Server Component trees, and update the DOM.
3. The JavaScript instructions are used to hydrate Client Components and make the application interactive.
1. サーバで生成された初期表示のための HTML を元に、すぐに非インタラクティブな画面を表示する
2. RSC Payload を元に、RSC と CC をツリー上で紐づけ、レンダリングする
3. JavaScript を Hydrate(Hydration) し、CC をインタラクティブにする
参考
https://zenn.dev/frontendflat/articles/nextjs-rscpayload-composition
常にレンダリングの流れは不変であり、サーバーサイド→クライアントサイドの順番で行われる
CCがレンダリングされるときにはすでにSCのレンダリングが完了しています。
CCからSCを読み込めてしまうと、その時点で新たなサーバーへのリクエストが発生してしまうので、CCにSCを読み込むことはできません。
code:ts
'use client'
import ServerComponent from './Server-Component'
export default function ClientComponent() {
return (
<>
<ServerComponent />
</>
)
}
一方で、SCをpropsとしてCCに渡すこと(Composition パターン)はできます。
code:ts
export default function Page() {
return (
<ClientComponent>
<ServerComponent />
</ClientComponent>
)
}
参考
実践Next.js ——App Routerで進化するWebアプリ開発
https://ja.react.dev/reference/rsc/server-components
https://nextjs.org/docs/app/building-your-application/rendering/server-components
https://zenn.dev/yuu104/articles/react-server-component#rsc%EF%BC%88ssr-あり%EF%BC%89のレンダリングプロセス
https://zenn.dev/frontendflat/articles/nextjs-rscpayload-composition
#React #Next.js